package com.emeraldparser.collect;

import com.google.common.annotations.VisibleForTesting;

/**
 * A transformed set such that each {@code F} element in the source set maps to precisely
 * one {@code T} element in the target set.
 * 
 * @author Adam Paynter
 *
 * @param <F> ("From") The type of element in the source set
 * @param <T> ("To") The type of element in the target set
 */
public abstract class OneToOneTransformedSet<F, T> extends AbstractTransformedSet<F, T> {

	protected abstract F unapply(T targetElement);

	@VisibleForTesting
	protected F unsafeUnapply(Object unsafeTargetElement) throws ClassCastException {
		@SuppressWarnings("unchecked")
		T targetElement = (T) unsafeTargetElement;
		try {
			return unapply(targetElement);
		} catch (ClassCastException e) {
			throw new IllegalArgumentException(e);
		}
	}

	@Override
	public boolean add(T e) {
		F sourceElement = unapply(e);
		return sourceSet().add(sourceElement);
	}

	@Override
	public void clear() {
		sourceSet().clear();
	}

	@Override
	public boolean contains(Object o) {
		F sourceElement;
		
		try {
			sourceElement = unsafeUnapply(o);
		} catch (IllegalArgumentException e) {
			return false;
		}
		
		return sourceSet().contains(sourceElement);
	}

	@Override
	public boolean remove(Object o) {
		F sourceElement;
		
		try {
			sourceElement = unsafeUnapply(o);
		} catch (IllegalArgumentException e) {
			return false;
		}
		
		return sourceSet().remove(sourceElement);
	}

}
